home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / newmake.arc / MAKE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1986-09-21  |  7.3 KB  |  351 lines

  1.  
  2. /* #define JRHDEBUG */
  3.  
  4. #include <stdio.h>
  5. #include <ctype.h>
  6. #include "make.h"
  7.  
  8. /*
  9.  *    MAKE - Maintain seperate source files
  10.  *
  11.  *    SYNOPSIS
  12.  *        MK [-f file] [-a] [-n] [-d] [name] ...
  13.  *           f: use 'file' instead of default makefile
  14.  *           a: assume all modules are obsolete (recompile everything)
  15.  *           n: don't recompile, just list steps to recompile
  16.  *           d: debugging (print tree, file info)
  17.  *           name: module name to recompile
  18.  *
  19.  *        'secret' options (not to be used by humans):
  20.  *           -ofile    'file' is the script file to write to
  21.  *
  22.  *    AUTHOR
  23.  *        Landon M. Dyer, Atari Inc.
  24.  *
  25.  *    Macro definition on command line
  26.  *
  27.  *       [-m name:def]
  28.  *
  29.  *    support added by Richard Hargrove of Texas Instruments,
  30.  *    September 21, 1986.
  31.  */
  32.  
  33. #define SCRIPTFILE "make$$$$.bat"       /* (default) script-listing file */
  34. #define INIT    "~INIT"                 /* initialization macro */
  35. #define DEINIT    "~DEINIT"               /* de-init macro */
  36. #define BEFORE    "~BEFORE"               /* the per-root 'startup' method */
  37. #define AFTER    "~AFTER"                /* the per-root 'wrapup' method */
  38.  
  39.  
  40. char *mfiles[] = {            /* default makefiles */
  41.     "makefile",
  42.  
  43. #ifdef VAXVMS
  44.     "[-]makefile",
  45.     "sys$login:makefile",
  46. #endif
  47.  
  48. #ifdef MSDOS
  49.     "..\makefile",
  50. #endif
  51.     ""
  52. };
  53.  
  54.  
  55. MACRO *mroot = NULL;        /* root of macro-list */
  56. FILENODE *froot = NULL;     /* root of filenode-list */
  57. FILENODE *firstf = NULL;    /* the very first filenode */
  58. FILE *mkfp = NULL;        /* script file */
  59. char *modnames[MAXMODS];    /* module-names mentioned in commandline */
  60. int modcount = 0;        /* #of module-names */
  61. int debug = 0;            /* nonzero: turn on debugging */
  62. int obsolete = 0;        /* nonzero: every file should be recompiled */
  63. int noscript = 0;        /* nonzero: print methods on standard output */
  64. char *scriptf = SCRIPTFILE;    /* default script file */
  65. DATE bigbang;            /* a date, the very earliest possible */
  66. DATE endoftime;         /* a date, the very last possible */
  67.  
  68.  
  69. main(argc, argv)
  70. int argc;
  71. char **argv;
  72. {
  73.     int arg, i;
  74.     char *mfile = NULL;
  75.     DATE adate();
  76.  
  77.     char macname [STRSIZ/4], *macstrng; /* jrh */
  78.  
  79.     bigbang = adate(0, 0);        /* init root dates */
  80.     endoftime = adate(~0, ~0);
  81.  
  82.     for(arg = 1; arg < argc; ++arg)
  83.         if(*argv[arg] == '-') switch(tolower(argv[arg][1]))
  84.         {
  85.            case 'f':
  86.             if(++arg >= argc)
  87.             {
  88.                 fprintf(stderr, "-f needs filename argument.\n")
  89. ;
  90.                 return;
  91.             }
  92.             mfile = argv[arg];
  93.             break;
  94.  
  95.            case 'a':
  96.             obsolete = 1;
  97.             break;
  98.  
  99.            case 'n':
  100.             noscript = 1;
  101.             break;
  102.  
  103.            case 'd':
  104.             debug = 1;
  105.             break;
  106.  
  107. /* jrh */
  108. #define MACSEP ':'
  109.            case 'm':
  110.             if(++arg >= argc) {
  111.               fprintf(stderr, "-m needs macro definition (1).\n");
  112.               return;
  113.             }
  114.             mexpand (argv [arg], macname, STRSIZ/4, MACCHAR);
  115.             escape (macname, COMCHAR);
  116.             macstrng = macname;
  117.  
  118.             while ((*macstrng != MACSEP) && (*macstrng != '\0')) {
  119.               macstrng++;
  120.             }
  121.             if ((*macstrng == MACSEP) &&
  122.                 (*macstrng++ = '\0', *macstrng != '\0')) {
  123.               defmac (macname, macstrng);
  124.             }
  125.             else {
  126.               fprintf(stderr, "-m needs macro definition (2).\n");
  127.               return;
  128.             }
  129.             break;
  130. /* end jrh */
  131.            case 'o':
  132.             scriptf = argv[arg] + 2;
  133.             break;
  134.  
  135.            default:
  136.             fprintf(stderr, "Unknown switch: %c\n", argv[arg][1]);
  137.             break;
  138.         } else if(modcount < MAXMODS)
  139.             modnames[modcount++] = argv[arg];
  140.         else
  141.         {
  142.             fprintf(stderr, "Too many module names.\n");
  143.             return;
  144.         }
  145.  
  146.     if(mfile != NULL)
  147.     {
  148.         if(fmake(mfile) == -1)
  149.             fprintf(stderr, "Cannot open makefile '%s'.\n", mfile);
  150.     } else {
  151.         for(i = 0; *mfiles[i]; ++i)
  152.             if(fmake(mfiles[i]) != -1) break;
  153.         if(!*mfiles[i])
  154.             fprintf(stderr, "Cannot open makefile.\n");
  155.     }
  156.  
  157.     if(debug) prtree();
  158. }
  159.  
  160.  
  161. /*
  162.  * Construct dependency tree from the makefile 'fn'.
  163.  * Figure out what has to be recompiled, and write a script file to do that.
  164.  */
  165. fmake(fn)
  166. char *fn;
  167. {
  168.     FILE *fp;
  169.  
  170.     if((fp = fopen(fn, "r")) == NULL) return -1;
  171.  
  172.     fparse(fp);
  173.     determ();
  174.  
  175.     fclose(fp);
  176.     return 0;
  177. }
  178.  
  179.  
  180. /*
  181.  * Parse the input file, defining macros and building the dependency tree.
  182.  */
  183. fparse(fp)
  184. FILE *fp;
  185. {
  186.     char ibuf[STRSIZ], ebuf[STRSIZ];
  187.     char *strp, *tok1, *tok2, *s;
  188.     FILENODE *lastf = NULL;
  189.     FILENODE *sf;
  190.  
  191.     for(;;)
  192.     {
  193.         if(fgets(ibuf, STRSIZ, fp) == NULL) break;
  194.         mexpand(ibuf, ebuf, STRSIZ, MACCHAR);
  195.         escape(ebuf, COMCHAR);
  196.  
  197.             /* clobber last newline in string */
  198.         s = ebuf + strlen(ebuf) - 1;
  199.         if(s >= ebuf && *s == '\n') *s = '\0';
  200.  
  201.         if(*ebuf == '\t')
  202.         {
  203.             addmeth(lastf, ebuf+1);
  204.             continue;
  205.         }
  206.  
  207.         strp = ebuf;
  208.         if((tok1 = token(&strp)) == NULL) continue;
  209.         if((tok2 = token(&strp)) != NULL)
  210.             if(!strcmp(tok2, DEFMAC))
  211.             {
  212.                 if(*strp) defmac(tok1, strp);
  213.                 else if(undefmac(tok1) < 0)
  214.                     fprintf(stderr,
  215.                       "Can't undefine macro '%s'\n", tok1);
  216.                 continue;
  217.             }
  218.             else if(!strcmp(tok2, DEPEND))
  219.             {
  220.                 addmeth(lastf, gmacro(AFTER));
  221.  
  222.                 lastf = filenode(tok1);
  223.                 if(firstf == NULL) firstf = lastf;
  224.                 lastf->fmake = NULL;
  225.  
  226.                 addmeth(lastf, gmacro(BEFORE));
  227.  
  228.                 lastf->fflag |= ROOTP;
  229.                 while((tok1 = token(&strp)) != NULL)
  230.                     addfile(lastf, tok1);
  231.                 continue;
  232.             }
  233.             else addfile(lastf, tok2);
  234.  
  235.         do {
  236.             addfile(lastf, tok1);
  237.         } while((tok1 = token(&strp)) != NULL);
  238.     }
  239.  
  240.     addmeth(lastf, gmacro(AFTER));
  241. }
  242.  
  243.  
  244. /*
  245.  * Determine sequence of recompiles from the creation dates.
  246.  * If there is anything to recompile, then create a script file full of commands
  247. .
  248.  */
  249. determ()
  250. {
  251.     FILENODE *f;
  252.     int i;
  253.     char *m;
  254.  
  255.     if(firstf == NULL)            /* empty tree */
  256.     {
  257.         printf("No changes.\n");
  258.         return;
  259.     }
  260.  
  261.     if(modcount == 0) examine(firstf, endoftime);
  262.     else for(i = 0; i < modcount; ++i)
  263.     {
  264.         if((f = gfile(modnames[i])) == NULL)
  265.         {
  266.             fprintf(stderr, "Can't find root '%s'.\n", modnames[i]);
  267.             continue;
  268.         }
  269.  
  270.         if(f->fflag & ROOTP == 0)
  271.         {
  272.             fprintf(stderr, "'%s' is not a root!\n", f->fname);
  273.             continue;
  274.         }
  275.         examine(f, endoftime);
  276.     }
  277.  
  278.     if(mkfp != NULL)
  279.     {
  280.         if((m = gmacro(DEINIT)) != NULL)
  281.         {
  282.             fputs(m, mkfp);
  283.             fputc('\n', mkfp);
  284.         }
  285.         fclose(mkfp);
  286.     } else printf("No changes.\n");
  287. }
  288.  
  289.  
  290. /*
  291.  * Examine filenode 'fnd' and see if it has to be recompiled.
  292.  * 'date' is the last-touched date of the node's father
  293.  * (or 'endoftime' if its a root file.)
  294.  * Root files with NO dependencies are assumed not to be up to date.
  295.  */
  296. examine(fnd, date)
  297. FILENODE *fnd;
  298. DATE date;
  299. {
  300.     int rebuildp = 0;
  301.     NODE *n;
  302.  
  303.     getdate(fnd);
  304.     if(fnd->fnode == NULL && fnd->fflag & ROOTP)
  305.         rebuildp = 1;
  306.     else for(n = fnd->fnode; n != NULL; n = n->nnext)
  307.         if(examine(n->nfile, fnd->fdate)) rebuildp = 1;
  308.  
  309.     if(rebuildp) recomp(fnd);
  310.     if(obsolete || laterdt(fnd->fdate, date) >= 0)
  311.         rebuildp = 1;
  312.     return rebuildp;
  313. }
  314.  
  315.  
  316. /*
  317.  * Make sure a filenode gets recompiled.
  318.  */
  319. recomp(f)
  320. FILENODE *f;
  321. {
  322.     FILENODE *sf;
  323.     char *m;
  324.  
  325.     if(mkfp == NULL)
  326.     {
  327.         if(noscript) mkfp = stdout;
  328.         else if((mkfp = fopen(scriptf, "w")) == NULL)
  329.             fprintf(stderr, "Cannot create: '%s'\n", scriptf);
  330.  
  331.     if((m = gmacro(INIT)) != NULL)
  332.         {
  333.             fputs(m, mkfp);
  334.             fputc('\n', mkfp);
  335.         }
  336.     }
  337.  
  338.     if(f->fflag & REBUILT) return;
  339.     if(f->fmake != NULL) fputs(f->fmake, mkfp);
  340.     f->fflag |= REBUILT;
  341. }
  342.  
  343.  
  344. /*
  345.  * Complain about being out of memory, and then die.
  346.  */
  347. allerr() {
  348.     fprintf(stderr, "Can't alloc -- no space left (I give up!)\n");
  349.     exit(1);
  350. }
  351.